package com.gmall.order.config;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

@Component
@Aspect //定义切面
public class Repeat2Aspect implements Ordered {

    @Autowired
    RedisTemplate redisTemplate;
    @Pointcut(value = "@annotation(com.gmall.order.annotation.Repeat2)")
    public void repeatMethodPointCut() {

    }

    @Around("repeatMethodPointCut()")
    public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
        //请求标识= 请求IP + 请求的URL + 参数
        HttpServletRequest request = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getRequest();

        //3秒内有一个完全相同的请求 ，我们认为重复提交
        //如何判断两个请求是一样的呢？IP，URL，参数，BODY
        /*HttpServletResponse response = ((ServletRequestAttributes)
                RequestContextHolder.getRequestAttributes()).getResponse();
        response.setHeader("RepeatUUID", UUID.randomUUID().toString());*/
        //IP地址
        String ipAddr = getRemoteHost(request);
        //请求的URL
        String url = request.getRequestURL().toString();
        //参数
        String reqParam = getParameterMap(joinPoint, request);
        String body = getRequestBody(request).replaceAll(" ","");
        String request_identification = ipAddr + ":" + url + ":" + reqParam + ":" + body;
        System.out.println(String.format("请求源IP:【%s】,请求URL:【%s】,请求参数:【%s】", ipAddr, url, reqParam));
        System.out.println(request_identification);
        ////判断redis中存在 请求标识，不存在，不是重复提交
        if(redisTemplate.hasKey(request_identification)){
            throw new RuntimeException(url + " 重复提交");
        }else{
            redisTemplate.opsForValue().set(request_identification,"OK",3, TimeUnit.SECONDS);
        }
        //        //保存到Redis中，设置过期时间3秒
        //        //存在，重复提交
        Object result = joinPoint.proceed();

        System.out.println(String.format("请求源IP:【%s】,请求URL:【%s】,返回参数:【%s】", ipAddr, url, result));
        return result;
    }

    /**
     * 获取目标主机的ip
     *
     * @param request
     * @return
     */
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }
    /**
     * 入参数据
     *
     * @param joinPoint
     * @param request
     * @return
     */
    private String getParameterMap(JoinPoint joinPoint, HttpServletRequest request) {

        String reqParam = "";
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        Annotation[] annotations = targetMethod.getAnnotations();
        for (Annotation annotation : annotations) {
            //此处可以改成自定义的注解
            if (annotation.annotationType().equals(RequestMapping.class)
                    || annotation.annotationType().equals(PostMapping.class)) {
                reqParam = JSON.toJSONString(request.getParameterMap());
                break;
            }
        }
        return reqParam;
    }

    public String getRequestBody(HttpServletRequest request) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String str, body = "";
        while ((str = reader.readLine()) != null) {
            body += str;
        }
        return body.trim();
    }



    @Override
    public int getOrder() {
        return -100;
    }
}
